import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Random;

/**
 * This class is used to handle the Encryption and Decryption of data
 * sent between the client and the server
 * @author Matthew
 *
 */
public class Crypt {
	/**
	 * Takes in a string to be encrypted and returns the encrypted
	 * byte sequence
	 * @param s - the string to be encrypted
	 * @return - The byte array of the encrypted data
	 */
	public static byte[] Encrypt(String s){
		if(s == null || s.length() == 0) return new byte[0];
		byte[] data1 = s.getBytes(); //Obtain the string's byte sequence
		byte[] data2 = new byte[data1.length * 2]; //prep the encrypted sequence
		Random r = new Random();
		int j = 0;
		//I will not explain the encrypting process, but it is done here.
		for(int i = 0; i < data1.length; i++){
			int shift = r.nextInt(5) + 1;
			data2[j] = Byte.parseByte(shift(getBin(Integer.toBinaryString(shift)), 1, false), 2); 
			j++;
			data2[j] = Byte.parseByte(shift(getBin(data1[i]), shift, false), 2);
			j++;
		}
		return data2; //return the encrypted data
	}
	/**
	 * Decrypts a sequence of bytes given from Encrypt.
	 * @param data1 - byte sequence from Encrypt
	 * @return - the original encrypted string
	 */
	public static String Decrypt(byte[] data1){
		if(data1 == null || data1.length == 0) return new String("");
		byte[] data2 = new byte[data1.length / 2]; //Prep for the string to be returned
		int j = 0;
		//I will not explain the decrypting process, but it is done here
		for(int i = 0; i < data1.length; i+=2){
			byte b = data1[i];
			byte b2 = data1[i + 1];
			int amt = Byte.parseByte(shift(getBin(b), 1, true), 2);
			data2[j] = Byte.parseByte(shift(getBin(b2), amt, true), 2);
			j++;
		}
		return new String(data2); //Returns the string originally encrypted
	}
	/**
	 * Shifting method for binary values
	 * @param binString - The string to be shifted
	 * @param amt - The amount of indexes to be shifted
	 * @param dirRight - True if to the right, false if to the left.
	 * @return - The shifted binary string
	 */
	private static String shift(String binString, int amt, boolean dirRight){
		if(amt == 0) return binString;
		else if(dirRight) return shift(binString.substring(binString.length() - 1) + 
				binString.substring(0, binString.length() - 1), amt - 1, dirRight);

		else return shift(binString.substring(1) + binString.substring(0, 1), amt - 1, dirRight);
	}
	/**
	 * Get the binary value of a byte
	 * @param b - the byte given
	 * @return - The binary representation  of the byte
	 */
	private static String getBin(byte b){
		String bin = Integer.toBinaryString(b);
		return getBin(bin);
	}
	/**
	 * This method ensures the even length of the binary given to it
	 * @param bin - The string to be evaluated
	 * @return - The binary string of the unifrom length
	 */
	private static String getBin(String bin){
		while(bin.length() < 7) bin = "0" + bin;
		return bin;
	}
	public static String Decrypt(byte[] buff, int read) {
		byte[] temp = new byte[read];
		for(int i = 0; i < read; i++){
			temp[i] = buff[i];
		}
		return Decrypt(temp);
	}
	public static void main(String[] args){
		try {
			FileInputStream fis = new FileInputStream(new File("MMsav1.sav"));
			byte[] data = new byte[fis.available()];
			fis.read(data);
			fis.close();
			String saveData = Crypt.Decrypt(data).trim();
			int index = saveData.indexOf("0");
			index = saveData.indexOf("0", index + 1);
			System.out.println(saveData);
			/*FileOutputStream fos = new FileOutputStream(new File("MMsav1.sav"));
			fos.write(Crypt.Encrypt(saveData));
			fos.close();*/
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}
